package org.example;

import javassist.*;

import java.lang.reflect.Modifier;

public class AppGenNewComplexCzBySsist2 {

    public static void main(String[] args) throws Exception {

        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = genericClass(pool);
        invokeInstance(ctClass);
    }

    private static CtClass genericClass(ClassPool pool) throws Exception {

        String postFix = "target/genComplexCzByJs2";
        String genClassDir = System.getProperty("user.dir") + "/javassistTest/" + postFix;
        System.out.println("生成的文件放在:" + postFix);

        CtClass ctClass = pool.makeClass("com.scy.Person");

        // 下面都是对这个ctClass的初始化
        // 添加private String name;属性
        CtField nameField = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
        nameField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(nameField);

        // 添加private int age;属性
        CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);
        ageField.setModifiers(Modifier.PRIVATE);
        ctClass.addField(ageField);

        // 添加getter and setter
        ctClass.addMethod(CtNewMethod.getter("getName", nameField));
        ctClass.addMethod(CtNewMethod.setter("setName", nameField));
        ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
        ctClass.addMethod(CtNewMethod.setter("setAge", ageField));

        // 添加无参构造器
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
        String body = "{\nname=\"zhangsan\";\nage=23;\n}";
        ctConstructor.setBody(body);
        ctClass.addConstructor(ctConstructor);

        //添加带入参和返回值的方法say
        CtMethod sayMethod = new CtMethod(pool.getCtClass("java.lang.String"), "say",
                new CtClass[]{pool.getCtClass("java.lang.String")}, ctClass);
        sayMethod.setModifiers(Modifier.PUBLIC);
        StringBuilder builder = new StringBuilder();
        builder.append("{\nSystem.out.println(\"Person类的say方法执行了\");\n");
        builder.append("return \"返回值是:\" + $1 ; \n}");
        sayMethod.setBody(builder.toString());
        ctClass.addMethod(sayMethod);

        ctClass.writeFile(genClassDir);

        return ctClass;
    }

    private static void invokeInstance(CtClass ctClass) throws Exception {
        // 完成真正的编译，形成字节码
        Class<?> clazz = ctClass.toClass();
        // 创建实例
        Object instance = clazz.newInstance();
        // 调用say()业务方法
        Object returnVal = instance.getClass()
                .getMethod("say", new Class[]{String.class})
                .invoke(instance, new Object[]{"你好china"});
        System.out.println(returnVal);
    }
}
